package compiler;

import interfaces.LexicalAnalyzer;

/**
 * Verifies that a token is a valid token by getting a token at a time
 * from the entire input string. Once it has a single token, if it begins 
 * with a hash tag it is checked to see if is is a valid lexical token by
 * running through the possible tokens array. If it is not a possible token 
 * a Lexical Error is thrown and the program is exited.
 * @author Zach
 *
 */
public class MyLexicalAnalyzer implements LexicalAnalyzer {

	int currentPosition = 0;
	String nextCharacter = "";
	
	@Override
	public void getNextToken() {
		getCharacter();
		while(isSpace(MyCompiler.token)){
			getCharacter();
		}
		if(MyCompiler.token.equals("#")){
			processTag();
			while(MyCompiler.token.endsWith(" ")){
				MyCompiler.token = MyCompiler.token.substring(0, MyCompiler.token.length() - 1);
			}
			if(!lookupToken()){
				System.err.print("LEXICAL ERROR! " + MyCompiler.token + " is not valid");
				System.exit(0);
			}
		}else{
			processText();
			if(MyCompiler.token.startsWith(" "))
				MyCompiler.token = MyCompiler.token.substring(1, MyCompiler.token.length());
		}
	}

	@Override
	public void getCharacter() {
		if((currentPosition + 1) > MyCompiler.entireInput.length()){
			System.err.println("The file is empty.. exitting program");
			System.exit(0);
		}
		char currentChar =  MyCompiler.entireInput.charAt(currentPosition);
		MyCompiler.token = currentChar + "";
		currentPosition++;
	}

	@Override
	public void addCharacter() {
		if((currentPosition + 1) > MyCompiler.entireInput.length()){
			System.err.println("LEXICAL ERROR! " + MyCompiler.token + " is not valid");
			System.exit(0);
		}
		char currentChar = MyCompiler.entireInput.charAt(currentPosition);
		nextCharacter = currentChar + "";
		currentPosition++;
	}

	@Override
	public boolean isSpace(String c) {
		if(c.equals(" ") || c.equals("\t") || c.equals("\r"))
			return true;
		else
			return false;
	}

	@Override
	public boolean lookupToken() {
		for(int i = 0; i < MyCompiler.possibleTokens.size(); i++){
			if(MyCompiler.token.equalsIgnoreCase(MyCompiler.possibleTokens.get(i).lol))
				return true;
		}
		return false;
	}

	/**
	 * Method called when a token is found and needs to be checked to see if 
	 * it is a valid token
	 */
	public void processTag(){
		addCharacter();
		while(!isSpace(nextCharacter) && !nextCharacter.equals("#") && (currentPosition + 1) <= MyCompiler.entireInput.length()){
			MyCompiler.token += nextCharacter;
			addCharacter();
		}
		if((currentPosition + 1) >  MyCompiler.entireInput.length()){
			MyCompiler.token += nextCharacter;
		}else{	
			 if(nextCharacter.equals("#")){
				 currentPosition--;
			 }
			if(!lookupToken()){
				processTwoOrThreeWordTag();
			}
			if(!lookupToken()){
				processTwoOrThreeWordTag();
			}
		}
	}
	
	/**
	 * Private method used by processTag to help distinguish between one,
	 * two and three word tags
	 */
	private void processTwoOrThreeWordTag(){
		MyCompiler.token += nextCharacter;
		addCharacter();
		while(!isSpace(nextCharacter) && !nextCharacter.equals("#")  && (currentPosition + 1) <= MyCompiler.entireInput.length()){
			MyCompiler.token += nextCharacter;
			addCharacter();
		}
		if((currentPosition + 1) >  MyCompiler.entireInput.length())
			MyCompiler.token += nextCharacter;
		else{	
			 if(nextCharacter.equals("#")){
				 currentPosition--;
			 }
		}
		
	}
	/**
	 * Method that processes text until it is the end of the string or if a hash tag is reached
	 */
	public void processText(){
		while(!nextCharacter.equals("#")  && (currentPosition + 1) <= MyCompiler.entireInput.length()){
			addCharacter();
			if(!nextCharacter.equals("#"))
				MyCompiler.token += nextCharacter;
		}
		if(nextCharacter.equals("#")){
			currentPosition--;
		}
	}
	
	/**
	 * Method that helps check to make sure that there isn't any text after the KTHXBYE tag
	 * @return true, if there is no text other than spaces after KTHXBYE, otherwise false
	 */
	public boolean checkRestOfInput(){
		while((currentPosition + 1) <= MyCompiler.entireInput.length()){
			addCharacter();
			if(!isSpace(nextCharacter)){
				return false;
			}
		}
		return true;
	}
	
}
